const mysqldump = require('mysqldump');
const fs = require('fs').promises;
const path = require('path');
const archiver = require('archiver');
const databaseConfig = require('../config/database');
const logger = require('../utils/logger');

class BackupService {
    constructor() {
        this.backupDir = process.env.BACKUP_DIR || './backups';
        this.retentionDays = parseInt(process.env.BACKUP_RETENTION_DAYS) || 7;
    }

    async ensureBackupDirectory() {
        try {
            await fs.access(this.backupDir);
        } catch (error) {
            logger.info(`创建备份目录: ${this.backupDir}`);
            await fs.mkdir(this.backupDir, { recursive: true });
        }
    }

    generateBackupFileName() {
        const now = new Date();
        const timestamp = now.toISOString()
            .replace(/:/g, '-')
            .replace(/\..+/, '');
        return `${databaseConfig.database}_backup_${timestamp}`;
    }

    async createDatabaseDump() {
        const fileName = this.generateBackupFileName();
        const sqlFilePath = path.join(this.backupDir, `${fileName}.sql`);
        
        logger.info(`开始创建数据库备份: ${databaseConfig.database}`);
        
        try {
            const result = await mysqldump({
                connection: {
                    host: databaseConfig.host,
                    port: databaseConfig.port,
                    user: databaseConfig.user,
                    password: databaseConfig.password,
                    database: databaseConfig.database,
                },
                dumpToFile: sqlFilePath,
                dump: databaseConfig.dumpOptions
            });

            logger.info(`数据库备份完成: ${sqlFilePath}`);
            return {
                sqlFilePath,
                fileName,
                success: true,
                tables: result.dump.schema ? Object.keys(result.dump.schema).length : 0
            };
        } catch (error) {
            logger.error(`数据库备份失败: ${error.message}`);
            throw error;
        }
    }

    async compressBackup(sqlFilePath, fileName) {
        const zipFilePath = path.join(this.backupDir, `${fileName}.zip`);
        
        logger.info(`开始压缩备份文件: ${fileName}`);
        
        return new Promise((resolve, reject) => {
            const output = require('fs').createWriteStream(zipFilePath);
            const archive = archiver('zip', {
                zlib: { level: 9 } // 最高压缩级别
            });

            output.on('close', () => {
                logger.info(`备份文件压缩完成: ${zipFilePath} (${archive.pointer()} bytes)`);
                resolve({
                    zipFilePath,
                    size: archive.pointer(),
                    success: true
                });
            });

            archive.on('error', (err) => {
                logger.error(`压缩备份文件失败: ${err.message}`);
                reject(err);
            });

            archive.pipe(output);
            archive.file(sqlFilePath, { name: `${fileName}.sql` });
            archive.finalize();
        });
    }

    async cleanupOldBackups() {
        logger.info(`清理超过 ${this.retentionDays} 天的旧备份文件`);
        
        try {
            const files = await fs.readdir(this.backupDir);
            const now = Date.now();
            const retentionMs = this.retentionDays * 24 * 60 * 60 * 1000;
            
            let deletedCount = 0;
            
            for (const file of files) {
                const filePath = path.join(this.backupDir, file);
                const stats = await fs.stat(filePath);
                
                if (now - stats.mtime.getTime() > retentionMs) {
                    await fs.unlink(filePath);
                    logger.info(`删除旧备份文件: ${file}`);
                    deletedCount++;
                }
            }
            
            logger.info(`清理完成，删除了 ${deletedCount} 个旧备份文件`);
            return { deletedCount, success: true };
        } catch (error) {
            logger.error(`清理旧备份文件失败: ${error.message}`);
            throw error;
        }
    }

    async cleanupTempFiles(sqlFilePath) {
        try {
            await fs.unlink(sqlFilePath);
            logger.info(`清理临时SQL文件: ${sqlFilePath}`);
        } catch (error) {
            logger.warn(`清理临时文件失败: ${error.message}`);
        }
    }

    async performBackup() {
        try {
            await this.ensureBackupDirectory();
            
            // 创建数据库备份
            const dumpResult = await this.createDatabaseDump();
            
            // 压缩备份文件
            const compressResult = await this.compressBackup(
                dumpResult.sqlFilePath, 
                dumpResult.fileName
            );
            
            // 清理临时SQL文件
            await this.cleanupTempFiles(dumpResult.sqlFilePath);
            
            // 清理旧备份
            const cleanupResult = await this.cleanupOldBackups();
            
            return {
                success: true,
                backupFile: compressResult.zipFilePath,
                fileName: `${dumpResult.fileName}.zip`,
                size: compressResult.size,
                tables: dumpResult.tables,
                deletedOldFiles: cleanupResult.deletedCount,
                timestamp: new Date().toISOString()
            };
            
        } catch (error) {
            logger.error(`备份过程失败: ${error.message}`);
            throw error;
        }
    }
}

module.exports = new BackupService(); 